import * as config from 'config'
import {InstanceType} from 'typegoose'
import {ConsumeRecordModel} from '../../database/models/consumeRecord';
import {GameActivityModel} from "../../database/models/gameActivity";
import {GamePrizeModel} from "../../database/models/gamePrize";
import {LipstickSeries, PlayerSeriesIncomeModel, SeriesIncomeModel} from "../../database/models/lipstickSeries";
import {Player, PlayerModel} from "../../database/models/player";
import {Product} from "../../database/models/Product";
import {expect, requestToApiServer, setupTestEnv, tearDownTestEnv} from './helper';

const lipstickResumeTimes = config.get<number>("game.lipstickResumeTimes")

describe('游戏——口红机', () => {

  let player: InstanceType<Player> = null
  let playerPoor: InstanceType<Player> = null
  let jwtPoor: string = null
  let lipstickSeries: InstanceType<LipstickSeries> = null
  let jwt: string = null
  let gift: InstanceType<Product> = null

  before(async () => {
    const env = await setupTestEnv()

    player = env.player
    lipstickSeries = env.lipstickSeries
    jwt = env.jwt
    gift = env.gift
    playerPoor = env.playerPoor
    jwtPoor = env.jwtPoor
  })

  after(async () => {
    return await tearDownTestEnv()
  })

  beforeEach(async () => {
    return await GameActivityModel.deleteMany({})
  })

  it('开始一次游戏', async function () {
    const playerBefore = await PlayerModel.findOne({_id: player.id});

    let cost
    let freeCost
    if (lipstickSeries.priceInCoin < playerBefore.freeCoin) {
      cost = 0
      freeCost = lipstickSeries.priceInCoin
    } else {
      cost = lipstickSeries.priceInCoin - playerBefore.freeCoin
      freeCost = playerBefore.freeCoin
    }

    await requestToApiServer()
      .post(`/game/start/${lipstickSeries._id}`)
      .set({'x-jwt': jwt})
      .then(async res => {
        expect(res.body).have.properties({ok: true, data: {new: true}})

        const playerAfter = await PlayerModel.findOne({_id: player.id})
        expect(playerAfter.coin).to.equal(playerBefore.coin - cost)
        expect(playerAfter.freeCoin).to.equal(playerBefore.freeCoin - freeCost)
      })

    const act = await GameActivityModel
      .findOne({player: player._id, lipstickSeries: lipstickSeries._id})
    expect(act).to.have.properties({state: `free`})

    const si = await SeriesIncomeModel.findOne({lipstickSeries: lipstickSeries._id})
    expect(si.income).to.equal(cost)

    const psi = await PlayerSeriesIncomeModel.findOne({lipstickSeries: lipstickSeries._id, player: player._id})
    expect(psi.income).to.equal(cost)

    const cr = await ConsumeRecordModel.findOne({objectId: lipstickSeries.id, player: player._id})
    expect(cr.coin).to.equal(cost)
    expect(cr.freeCoin).to.equal(freeCost)
  })

  /*
  it('[接口停用]开始游戏,没有金币,那就付钱(支付宝/微信)，没付返回又点击开始了游戏', async function () {

    let lipstickGameOrder: InstanceType<LipstickGameOrder>
    await requestToApiServer()
      .post(`/game/start/${lipstickSeries._id}`)
      .set({'x-jwt': jwtPoor})
      .then(async res => {
        expect(res.body).have.properties(
          {
            ok: false,
            error: "NO_ENOUGH_COIN"
          })
      })

    await requestToApiServer()
      .post(`/game/RMBStart/${lipstickSeries._id}`)
      .set({'x-jwt': jwtPoor})
      .send({payType: 'aliPay'})
      .expect(200)

    await requestToApiServer()
      .post(`/game/RMBStart/${lipstickSeries._id}`)
      .set({'x-jwt': jwtPoor})
      .send({payType: 'wechatPay'})
      .then(({body}) => {
        lipstickGameOrder = body.data.lipstickGameOrder
      })

    await requestToApiServer()
      .get(`/game/lipstickOrder/${lipstickGameOrder._id}`)
      .set({'x-jwt': jwtPoor})
      .then(({body}) => {
        expect(body.ok).to.equal(false)
      })

    await requestToApiServer()
      .post(`/game/start/${lipstickSeries._id}`)
      .set({'x-jwt': jwtPoor})
      .then(res => {
        expect(res.body).have.properties(
          {
            ok: false,
            error: "NO_ENOUGH_COIN"
          })
      })
  })
  */
  /*
  it('[接口停用]开始游戏,没有金币,那就付钱(支付宝/微信)', async function () {

    let lipstickGameOrder: InstanceType<LipstickGameOrder>
    await requestToApiServer()
      .post(`/game/start/${lipstickSeries._id}`)
      .set({'x-jwt': jwtPoor})
      .then( res => {
        expect(res.body).have.properties(
          {
            ok: false,
            error: "NO_ENOUGH_COIN"
          })
      })

    await requestToApiServer()
      .post(`/game/RMBStart/${lipstickSeries._id}`)
      .set({'x-jwt': jwtPoor})
      .send({payType: 'aliPay'})
      .expect(200)

    await requestToApiServer()
      .post(`/game/RMBStart/${lipstickSeries._id}`)
      .set({'x-jwt': jwtPoor})
      .send({payType: 'wechatPay'})
      .then(({body}) => {
        lipstickGameOrder = body.data.lipstickGameOrder
      })

    const payOrder = await PaymentOrderModel.findOne({
      orderType: 'LipstickGameOrder', order: lipstickGameOrder._id
    })

    const notification = {
      out_trade_no: payOrder.id,
      result_code: 'SUCCESS', return_code: 'SUCCESS',
    }
    const sign = wechatPayAuther.sign(notification)
    const xml = XMLbuilder.buildObject({...notification, sign})
    const res = await requestToApiServer()
      .post('/wechatpay/notify')
      .type('xml')
      .send(xml)
      .expect(200)
      .then(res => {
        expect(res.text).to.equal('<xml><return_code><![CDATA[SUCCESS]]></return_code></xml>')
      })

    expect(await PaymentOrderModel.findOne({
      orderType: 'LipstickGameOrder', order: lipstickGameOrder._id
    })).to.have.properties({state: 'finished'})

    expect(await LipstickGameOrderModel.findById(lipstickGameOrder._id).lean())
      .to.have.properties({state: 'paid'})

    const act = await GameActivityModel
      .findOne({player: playerPoor._id, lipstickSeries: lipstickSeries._id})
    expect(act).to.have.properties({isPayRMB: true})

    let activity = null
    await requestToApiServer()
      .get(`/game/lipstickOrder/${lipstickGameOrder._id}`)
      .set({'x-jwt': jwtPoor})
      .then(({body}) => {
        activity = body.data.activity
      })
    const lgo = await LipstickGameOrderModel.findById(lipstickGameOrder)
      .populate(`activity`).lean()
    expect(lgo.activity.canWin).to.equal(activity.canWin)

    const pr = await PlayerModel.findOne({_id: playerPoor.id});
    expect(pr.coin).to.equal(0)
    expect(pr.freeCoin).to.equal(0)
  })
  */

  it('第一次游戏未结束，随便开始一把都会继续上局游戏信息', async function () {

    let currentActivityData
    await requestToApiServer()
      .post(`/game/start/${lipstickSeries._id}`)
      .set({'x-jwt': jwt})
      .then(res => {
        expect(res.body).to.have.properties({ok: true})
        currentActivityData = res.body.data
      })

    await requestToApiServer()
      .post(`/game/start/any_series_id`)
      .set({'x-jwt': jwt})
      .then(res => {
        expect(res.body).to.have.properties({
          ok: true, data: {
            ...currentActivityData, new: false
          }
        })
      })
  })

  context(`付钱复活游戏`, () => {

    let currentActivityData = null
    beforeEach(async () => {
      await requestToApiServer()
        .post(`/game/start/${lipstickSeries._id}`)
        .set({'x-jwt': jwt})
        .then(res => {
          expect(res.body).to.have.properties({ok: true})
          currentActivityData = res.body.data
        })

      await requestToApiServer()
        .post(`/game/claim/${currentActivityData.activity}`)
        .set({'x-jwt': jwt})
        .send({win: false, stage: 0})
        .expect(200)
        .then(res => {
          expect(res.body).to.have.properties({
            ok: true, data: {
              win: false,
              gift: {
                ok: true
              }
            }
          })
        })
    })
    it('coin复活', async function () {

      return
      // @ts-ignore
      const playerBefore = await PlayerModel.findOne({_id: player.id});

      const times = []
      for (let i = 1; i <= lipstickResumeTimes; i++) {
        times.push(i)
      }
      for (const it of times) {
        await requestToApiServer()
          .post(`/lipstickSeries/lipstickGameOrder/${currentActivityData.activity}`)
          .send({payType: 'coin'})
          .set({'x-jwt': jwt})
          .then(({body}) => {
            expect(body.data.activity._id).to.equal(currentActivityData.activity)
          })

        let actModel = await GameActivityModel.findById(currentActivityData.activity).lean()
        expect(actModel).to.have.properties({state: 'free', resumeTimes: it})

        await requestToApiServer()
          .post(`/game/claim/${currentActivityData.activity}`)
          .set({'x-jwt': jwt})
          .send({win: false, stage: 0})
          .expect(200)
          .then(res => {
            expect(res.body).to.have.properties({
              ok: true, data: {
                win: false
              }
            })
          })

        actModel = await GameActivityModel.findById(currentActivityData.activity).lean()
        expect(actModel).to.have.properties({state: 'done', resumeTimes: it})
      }

      const p = await PlayerModel.findOne({_id: player.id});
      expect(p.coin + p.freeCoin).to.equal(playerBefore.coin + playerBefore.freeCoin - lipstickResumeTimes * lipstickSeries.priceInCoin)

      await requestToApiServer()
        .post(`/lipstickSeries/lipstickGameOrder/${currentActivityData.activity}`)
        .send({payType: 'coin'})
        .set({'x-jwt': jwt})
        .then(({body}) => {
          expect(body).have.properties(
            {
              ok: false,
              error: "OVER_RESUME_LIMIT"
            })
        })
    })

    /*
    it('[接口停用]wechatPay/aliPay复活', async function () {

      const playerBefore = await PlayerModel.findOne({_id: player.id});
      let lipstickGameOrder: InstanceType<LipstickGameOrder>
      await requestToApiServer()
        .post(`/lipstickSeries/lipstickGameOrder/${currentActivityData.activity}`)
        .send({payType: 'wechatPay'})
        .set({'x-jwt': jwt})
        .then(({body}) => {
          lipstickGameOrder = body.data.lipstickGameOrder
        })

      const payOrder = await PaymentOrderModel.findOne({
        orderType: 'LipstickGameOrder', order: lipstickGameOrder._id
      })
      const notification = {
        out_trade_no: payOrder.id,
        result_code: 'SUCCESS', return_code: 'SUCCESS',
      }
      const sign = wechatPayAuther.sign(notification)
      const xml = XMLbuilder.buildObject({...notification, sign})
      const res = await requestToApiServer()
        .post('/wechatpay/notify')
        .type('xml')
        .send(xml)
        .expect(200)
        .then(res => {
          expect(res.text).to.equal('<xml><return_code><![CDATA[SUCCESS]]></return_code></xml>')
        })

      expect(await PaymentOrderModel.findOne({
        orderType: 'LipstickGameOrder', order: lipstickGameOrder._id
      })).to.have.properties({state: 'finished'})

      expect(await LipstickGameOrderModel.findById(lipstickGameOrder._id).lean())
        .to.have.properties({state: 'paid', payFor: 'resume'})

      const actModel = await GameActivityModel.findById(currentActivityData.activity).lean()
      expect(actModel).to.have.properties({state: 'free', resumeTimes: 1})
      expect(actModel.endAt).to.above(new Date())

      const p = await PlayerModel.findOne({_id: player.id});
      expect(p.coin + p.freeCoin).to.equal(playerBefore.coin + playerBefore.freeCoin)
    })
    */

  })

  it('上报游戏结束——失败且领gift奖', async function () {

    let currentActivityData = null
    await requestToApiServer()
      .post(`/game/start/${lipstickSeries._id}`)
      .set({'x-jwt': jwt})
      .then(res => {
        expect(res.body).to.have.properties({ok: true})
        currentActivityData = res.body.data
      })

    await requestToApiServer()
      .post(`/game/claim/${currentActivityData.activity}`)
      .set({'x-jwt': jwt})
      .send({win: false, stage: 0})
      .expect(200)
      .then(res => {
        expect(res.body).to.have.properties({
          ok: true, data: {
            win: false,
            gift: {
              ok: true
            }
          }
        })
      })

    const actModel = await GameActivityModel.findById(currentActivityData.activity)
    expect(actModel).to.have.properties({state: 'done'})

    const prize = await GamePrizeModel.findOne({player: player._id})
    expect(prize).to.have.properties({from: 'freeGift', state: 'idle', selectState: `notAllowed`})
  })

  it('上报游戏结束后，可以开始新游戏', async function () {

    let currentActivityData = null
    await requestToApiServer()
      .post(`/game/start/${lipstickSeries._id}`)
      .set({'x-jwt': jwt})
      .then(res => {
        expect(res.body).to.have.properties({ok: true})
        currentActivityData = res.body.data
      })

    await requestToApiServer()
      .post(`/game/claim/${currentActivityData.activity}`)
      .set({'x-jwt': jwt})
      .send({win: false, stage: 0})
      .expect(200)
      .then(res => {
        expect(res.body).to.have.properties({
          ok: true, data: {
            win: false,
            gift: {
              ok: true
            }
          }
        })
      })

    await requestToApiServer()
      .post(`/game/start/${lipstickSeries._id}`)
      .set({'x-jwt': jwt})
      .then(res => {
        expect(res.body).to.have.properties({ok: true, data: {'new': true}})
      })
  })

  context('游戏状态记录', function () {
    it('PUT 记录游戏状态、GET 获取', async () => {

      let activity = ''
      await requestToApiServer()
        .post(`/game/start/${lipstickSeries._id}`)
        .set({'x-jwt': jwt})
        .then(res => {
          expect(res.body.ok).to.be.true
          activity = res.body.data.activity
        })

      await requestToApiServer()
        .put(`/game/activity/state/${activity}`)
        .set({'x-jwt': jwt})
        .send({you: 'can put any thing here'})
        .then(res => {
          expect(res.body.ok).to.be.true
        })

      await requestToApiServer()
        .get(`/game/activity/state/${activity}`)
        .set({'x-jwt': jwt})
        .then(({body}) => {
          expect(body).to.have.properties({
            ok: true, data: {you: 'can put any thing here'}
          })
        })
    })

  })

  context('当前游戏查询', async () => {

    it('当前无游戏', async () => {
      await requestToApiServer()
        .get(`/game/my/activity/lipstick`)
        .set({'x-jwt': jwt})
        .then(res => {
          expect(res.body).to.have.properties({
            ok: true, data: {activity: null}
          })
        })
    })

    it('当前有游戏', async () => {

      let activity = ''
      await requestToApiServer()
        .post(`/game/start/${lipstickSeries._id}`)
        .set({'x-jwt': jwt})
        .then(res => {
          expect(res.body.ok).to.be.true
          activity = res.body.data.activity
        })

      await requestToApiServer()
        .get(`/game/my/activity/lipstick`)
        .set({'x-jwt': jwt})
        .then(res => {
          expect(res.body).to.have.properties({
            ok: true, data: {activity: {_id: activity}}
          })
        })
    })
  })
})
